import React, { useState, useEffect, useCallback, useRef } from 'react';
import { Input, Button, List, Card, message, Spin, Typography, Popconfirm, Tooltip, notification, Tabs, Tag, Modal, Form, InputNumber, Progress, Checkbox, Divider, Dropdown, Menu, Radio } from 'antd';
import { SaveOutlined, SyncOutlined, ForkOutlined, EditOutlined, CheckOutlined, StarOutlined, StarFilled, UserOutlined, RocketOutlined, ExclamationCircleOutlined, FileOutlined, FolderOutlined, DownloadOutlined, ToolOutlined, DeleteOutlined, UndoOutlined } from '@ant-design/icons';
import './GitManager.css';

const { Title, Text, Paragraph } = Typography;
const { Search } = Input;
const { TabPane } = Tabs;

const API_HOST = window.location.hostname;
const API_PORT = 3001;
const API_BASE_URL = `http://${API_HOST}:${API_PORT}`;
const WS_URL = `ws://${API_HOST}:${API_PORT}`;

const GitManager = () => {
  const [repoPath, setRepoPath] = useState('');
  const [inputRepoPath, setInputRepoPath] = useState('');
  const [branches, setBranches] = useState([]);
  const [loading, setLoading] = useState(false);
  const [loadingBranches, setLoadingBranches] = useState(false);
  const [currentBranch, setCurrentBranch] = useState('');
  const [editingRemark, setEditingRemark] = useState(null);
  const [remarkInput, setRemarkInput] = useState('');
  const [activeTab, setActiveTab] = useState('favorites');
  const [pullingBranch, setPullingBranch] = useState(null);
  const [onlineUsers, setOnlineUsers] = useState([]);

  // New states for production config and deployment
  const [productionBranch, setProductionBranch] = useState('');
  const [sshConfig, setSshConfig] = useState({ host: '', port: 22, username: '', privateKeyPath: '', remotePath: '', buildDir: 'dist', defaultPerms: '755', owner: 'www:www' });
  const [isDeploying, setIsDeploying] = useState(false);
  const [isTestingSsh, setIsTestingSsh] = useState(false);
  const [isDeployModalVisible, setIsDeployModalVisible] = useState(false);
  const [deployLogs, setDeployLogs] = useState([]);
  const [isUploading, setIsUploading] = useState(false);
  const [uploadProgress, setUploadProgress] = useState(0);
  const [currentStage, setCurrentStage] = useState(''); // 'zip' or 'upload'

  // State for conflict resolution modal
  const [isConflictModalVisible, setIsConflictModalVisible] = useState(false);
  const [conflictFiles, setConflictFiles] = useState([]);
  const [selectedFiles, setSelectedFiles] = useState([]);

  // State for dependency management
  const [isDepsModalVisible, setIsDepsModalVisible] = useState(false);
  const [isInstallingDeps, setIsInstallingDeps] = useState(false);
  const [isRemovingDeps, setIsRemovingDeps] = useState(false);
  const [depsLogs, setDepsLogs] = useState([]);
  const [depsProgress, setDepsProgress] = useState(0);
  const [selectedPackageManager, setSelectedPackageManager] = useState('npm');
  const [packageManagerStatus, setPackageManagerStatus] = useState({
    npm: true, // npm is always available
    pnpm: false,
    yarn: false
  });
  const [isRestoring, setIsRestoring] = useState(false);

  const [configForm] = Form.useForm();
  const ws = useRef(null);
  const dataFetchedRef = useRef(false);
  const deployLogRef = useRef(null);
  const depsLogRef = useRef(null);

  useEffect(() => {
    if (deployLogRef.current) {
      deployLogRef.current.scrollTop = deployLogRef.current.scrollHeight;
    }
  }, [deployLogs]);

  useEffect(() => {
    if (depsLogRef.current) {
      depsLogRef.current.scrollTop = depsLogRef.current.scrollHeight;
    }
  }, [depsLogs]);

  const fetchBranches = useCallback(async () => {
    if (loadingBranches) return;
    setLoadingBranches(true);
    try {
      const response = await fetch(`${API_BASE_URL}/api/git/branches`);
      const result = await response.json();
      if (result.success) {
        setBranches(result.data.branches);
        setCurrentBranch(result.data.current);
        // The production branch is now part of the config, but we can update it here too
        if (result.data.productionBranch) {
          setProductionBranch(result.data.productionBranch);
          configForm.setFieldsValue({ productionBranch: result.data.productionBranch });
        }
      } else {
        message.error(result.message || '获取分支列表失败');
        setBranches([]);
      }
    } catch (error) {
      message.error('获取分支时出错');
    } finally {
      setLoadingBranches(false);
    }
  }, [loadingBranches, configForm]);
  
  const fetchConfig = useCallback(async () => {
    setLoading(true);
    try {
      const response = await fetch(`${API_BASE_URL}/api/git/config`);
      const result = await response.json();
      if (result.success) {
        const { repoPath, productionBranch, sshConfig: fetchedSshConfig } = result.data;
        setRepoPath(repoPath);
        setInputRepoPath(repoPath);
        setProductionBranch(productionBranch || '');
        const fullSshConfig = { host: '', port: 22, username: '', privateKeyPath: 'public/blacktom-deploy', remotePath: '', buildDir: 'dist', defaultPerms: '755', owner: 'www:www', ...fetchedSshConfig };
        setSshConfig(fullSshConfig);
        
        configForm.setFieldsValue({
            productionBranch: productionBranch || '',
            ...fullSshConfig
        });

        if (repoPath) {
          fetchBranches();
          fetchPackageManagerStatus();
        }
      } else {
        message.error(result.message || '获取配置失败');
      }
    } catch (error) {
      message.error('无法连接到服务器');
    } finally {
      setLoading(false);
    }
  }, [fetchBranches, configForm]);

  const fetchPackageManagerStatus = useCallback(async () => {
    try {
      const response = await fetch(`${API_BASE_URL}/api/git/package-managers`);
      const result = await response.json();
      if (result.success) {
        setPackageManagerStatus(result.data);
      }
    } catch (error) {
      console.error('获取包管理器状态失败:', error);
    }
  }, []);

  useEffect(() => {
    if (dataFetchedRef.current) return;
    dataFetchedRef.current = true;
    fetchConfig();
  }, [fetchConfig]);

  const handlePull = useCallback(async (branchName) => {
    if (!branchName || pullingBranch) return;
    setPullingBranch(branchName);
    const key = `pull_${branchName}`;
    message.loading({ content: `正在拉取 ${branchName}...`, key });
    try {
      const response = await fetch(`${API_BASE_URL}/api/git/pull`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ branch: branchName }),
      });
      const result = await response.json();
      if (result.success) {
        message.success({ content: `分支 '${result.branch}' 拉取成功`, key });
      } else {
        message.error({ content: result.message || '拉取失败', key });
      }
    } catch (error) {
      message.error({ content: '拉取时出错', key });
    } finally {
      setPullingBranch(null);
    }
  }, [pullingBranch]);

  useEffect(() => {
    ws.current = new WebSocket(WS_URL);

    ws.current.onopen = () => {
      console.log('GitManager WebSocket connected');
      ws.current.send(JSON.stringify({ type: 'page_identify', page: 'git' }));
    };

    ws.current.onmessage = (event) => {
      const msg = JSON.parse(event.data);

      if (msg.type === 'deploy_progress' || msg.type === 'deploy_log') {
        handleWsLog(msg);
        return;
      }
      
      if (msg.type === 'deps_progress' || msg.type === 'deps_log' || msg.type === 'remove_deps_progress' || msg.type === 'remove_deps_log') {
        handleWsDepsLog(msg);
        return;
      }
      
      if (msg.type === 'deploy_conflict') {
        setConflictFiles(msg.files);
        setSelectedFiles(msg.files.map(f => f.name)); // Default to all selected
        setIsConflictModalVisible(true);
        return;
      }

      if (msg.type === 'git_users_update') {
        setOnlineUsers(msg.users);
        return;
      }

      if (msg.type === 'git_event') {
        if (msg.event === 'favorite_toggled' || msg.event === 'remark_updated') {
          setBranches(prev => prev.map(b => b.name === msg.branch ? { ...b, ...msg } : b));
          return;
        }

        if (msg.event === 'config_updated') {
            const { productionBranch, sshConfig: newSshConfig } = msg.config;
            setProductionBranch(productionBranch || '');
            const fullSshConfig = { host: '', port: 22, username: '', privateKeyPath: 'public/blacktom-deploy', remotePath: '', buildDir: 'dist', defaultPerms: '755', owner: 'www:www', ...newSshConfig };
            setSshConfig(fullSshConfig);
            configForm.setFieldsValue({
                productionBranch: productionBranch || '',
                ...fullSshConfig
            });
            notification.info({
              message: '配置已更新',
              description: '另一位用户更新了Git配置，您的视图已同步。',
            });
            return;
        }

        if (msg.event === 'checkout') {
          // 只在分支实际发生变化时才显示通知
          if (currentBranch !== msg.branch) {
            const key = `git_notification_${Date.now()}`;
            const btn = (
              <Button type="primary" size="small" onClick={() => {
                notification.close(key);
                handlePull(msg.branch);
              }}>
                拉取最新代码
              </Button>
            );
            
            setCurrentBranch(msg.branch);
            
            notification.info({
              message: '分支已自动切换',
              description: `${msg.message}。您的视图已同步。`,
              btn,
              key,
              duration: 15,
            });
          }
        }

        if (msg.event === 'restore') {
          notification.warning({
            message: '代码已被还原',
            description: `${msg.message}。所有未提交的改动已被放弃。`,
            duration: 10,
          });
        }
      }
    };

    ws.current.onclose = () => console.log('GitManager WebSocket disconnected');
    return () => ws.current.close();
  }, [handlePull, setCurrentBranch, configForm]);

  const handleWsLog = (msg) => {
    if (msg.type === 'deploy_progress') {
      setUploadProgress(msg.progress);
      if (msg.stage) setCurrentStage(msg.stage);
      return;
    }

    if (msg.type === 'deploy_log') {
      const log = msg.log;
      setDeployLogs(prevLogs => [...prevLogs, log]);

      if (log.includes('正在创建压缩包')) {
        setIsUploading(true);
        setCurrentStage('zip');
        setUploadProgress(0);
      }
      if (log.includes('正在上传 deploy.zip')) {
        setCurrentStage('upload');
        setUploadProgress(0);
      }
      if (log.includes('文件上传成功') || log.includes('部署成功') || log.includes('部署已取消') || log.includes('部署失败') || log.includes('测试成功')) {
        setIsUploading(false);
      }

      if (log.includes('部署成功完成') || log.includes('部署已取消') || log.includes('部署失败') || log.includes('快速部署测试成功完成')) {
        setIsDeploying(false);
        setIsTestingSsh(false);
        setIsUploading(false);
      }
      return;
    }
  };

  const handleWsDepsLog = (msg) => {
    if (msg.type === 'deps_progress' || msg.type === 'remove_deps_progress') {
      setDepsProgress(msg.progress);
      return;
    }

    if (msg.type === 'deps_log' || msg.type === 'remove_deps_log') {
      const log = msg.log;
      setDepsLogs(prevLogs => [...prevLogs, log]);

      if (log.includes('依赖安装完成') || log.includes('安装失败') || log.includes('安装已取消')) {
        setIsInstallingDeps(false);
        setDepsProgress(0);
        
        // 如果安装成功，更新包管理器状态
        if (log.includes('依赖安装完成')) {
          fetchPackageManagerStatus();
        }
      }

      if (log.includes('依赖移除完成') || log.includes('移除失败') || log.includes('移除已取消')) {
        setIsRemovingDeps(false);
        setDepsProgress(0);
      }
      return;
    }
  };

  const handleSaveProductionConfig = async (values) => {
    setLoading(true);
    try {
      const response = await fetch(`${API_BASE_URL}/api/git/config`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          productionBranch: values.productionBranch,
          sshConfig: {
            host: values.host,
            port: values.port,
            username: values.username,
            privateKeyPath: values.privateKeyPath,
            remotePath: values.remotePath,
            buildDir: values.buildDir,
            defaultPerms: values.defaultPerms,
            owner: values.owner,
          }
        }),
      });
      const result = await response.json();
      if (result.success) {
        message.success('生产环境配置已保存');
        setProductionBranch(result.data.productionBranch);
        setSshConfig(result.data.sshConfig);
        // 更新表单显示值
        configForm.setFieldsValue({
          productionBranch: result.data.productionBranch,
          ...result.data.sshConfig
        });
      } else {
        message.error(result.message || '保存配置失败');
      }
    } catch (error) {
      message.error('保存配置时出错');
    } finally {
      setLoading(false);
    }
  };

  const handleDeploy = async (branchName, password) => {
    // 1. Verify password and start deployment process on backend
    try {
        const startResponse = await fetch(`${API_BASE_URL}/api/git/deploy`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ branch: branchName, password }),
        });

        if (!startResponse.ok) {
            const result = await startResponse.json();
            message.error(result.message || '启动部署失败');
            return Promise.reject(result.message); // Reject to keep modal open on failure
        }
    } catch (error) {
        message.error('部署请求失败');
        return Promise.reject(error);
    }
    
    // 2. If start is successful, show the log modal and set state
    setIsDeploying(true);
    setDeployLogs([]);
    setIsDeployModalVisible(true);
    setUploadProgress(0);
    setIsUploading(false);
    setCurrentStage('');
  };

  const showDeployConfirm = (branchName) => {
    let passwordInput = '';
    Modal.confirm({
        title: '部署操作校验',
        icon: <RocketOutlined />,
        content: (
          <div>
            <p>请输入校验密码以开始部署分支: <strong>{branchName}</strong></p>
            <Input.Password
                autoFocus
                placeholder="请输入密码"
                onChange={(e) => {
                    passwordInput = e.target.value;
                }}
            />
          </div>
        ),
        okText: "确认并部署",
        cancelText: "取消",
        onOk: async () => {
            if (!passwordInput) {
                message.error('密码不能为空');
                return Promise.reject('密码不能为空');
            }
            await handleDeploy(branchName, passwordInput);
        },
    });
  };

  const handleSaveRepoPath = async (path) => {
    setLoading(true);
    try {
      const response = await fetch(`${API_BASE_URL}/api/git/repo`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ repoPath: path }),
      });
      const result = await response.json();
      if (result.success) {
        message.success(result.message);
        setRepoPath(path);
        fetchBranches();
      } else {
        message.error(result.message || '保存失败');
      }
    } catch (error) {
      message.error('保存路径时出错');
    } finally {
      setLoading(false);
    }
  };

  const handleCheckout = async (branch) => {
    const key = 'checkout_message';
    message.loading({ content: `正在切换到 ${branch}...`, key });
    try {
      const response = await fetch(`${API_BASE_URL}/api/git/checkout`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ branch }),
      });
      const result = await response.json();
      if (result.success) {
        message.success({ content: result.message, key });
        setCurrentBranch(branch);
      } else {
        message.error({ content: '切换失败', key });
        notification.error({ message: '分支切换失败', description: result.message, duration: 10 });
        if (result.message.includes('不存在')) {
          fetchBranches();
        }
      }
    } catch (error) {
      message.error({ content: '切换分支时发生网络错误', key });
    }
  };

  const handleSaveRemark = async (branchName) => {
    const originalBranches = [...branches];
    setBranches(prev => prev.map(b => b.name === branchName ? { ...b, remark: remarkInput } : b));
    setEditingRemark(null);
    try {
      const response = await fetch(`${API_BASE_URL}/api/git/remark`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ branch: branchName, remark: remarkInput }),
      });
      const result = await response.json();
      if (result.success) {
        message.success('备注已保存');
        setRemarkInput('');
      } else {
        message.error(result.message || '保存备注失败');
        setBranches(originalBranches);
      }
    } catch (error) {
      message.error('保存备注时出错');
      setBranches(originalBranches);
    }
  };

  const handleToggleFavorite = async (branchName, currentIsFavorite) => {
    const newIsFavorite = !currentIsFavorite;
    setBranches(prev => prev.map(b => b.name === branchName ? { ...b, isFavorite: newIsFavorite } : b));
    try {
      const response = await fetch(`${API_BASE_URL}/api/git/favorite`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ branch: branchName, isFavorite: newIsFavorite }),
      });
      const result = await response.json();
      if (!result.success) {
        message.error(result.message || '操作失败');
        setBranches(prev => prev.map(b => b.name === branchName ? { ...b, isFavorite: currentIsFavorite } : b));
      }
    } catch (error) {
      message.error('更新常用状态时出错');
      setBranches(prev => prev.map(b => b.name === branchName ? { ...b, isFavorite: currentIsFavorite } : b));
    }
  };

  const filteredBranches = branches.filter(branch => {
    if (activeTab === 'favorites') return branch.isFavorite;
    if (activeTab === 'others') return !branch.isFavorite;
    return true;
  });

  const handleCancelDeploy = async (branchName) => {
    try {
        const response = await fetch(`${API_BASE_URL}/api/git/deploy/cancel`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ branch: branchName }),
        });
        const result = await response.json();
        if (result.success) {
            message.warning('取消部署请求已发送。');
        } else {
            message.error(result.message || '取消失败');
        }
    } catch (error) {
        message.error('发送取消请求时出错');
    }
  };

  const handleTestSsh = async () => {
    setIsTestingSsh(true);
    setDeployLogs([]);
    setIsDeployModalVisible(true);
    setUploadProgress(0);
    setIsUploading(false);
    setCurrentStage('');

    try {
        const response = await fetch(`${API_BASE_URL}/api/git/ssh-test`, {
            method: 'POST'
        });
        if (!response.ok) {
            const result = await response.json();
            message.error(result.message || '发起测试失败');
            setIsTestingSsh(false);
        }
    } catch (error) {
        message.error(`发起测试时出错: ${error.message}`);
        setIsTestingSsh(false);
    }
  };

  const handleResolveConflict = async (overwriteItems) => {
    setIsConflictModalVisible(false);
    try {
        const response = await fetch(`${API_BASE_URL}/api/git/deploy/resolve`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ overwriteItems }),
        });
        const result = await response.json();
        if (response.ok) {
            message.success(result.message || '操作成功');
        } else {
            message.error(result.message || '操作失败');
        }
    } catch (error) {
        message.error('请求失败');
    }
  };

  const handleCancelConflict = async () => {
    setIsConflictModalVisible(false);
    try {
        const response = await fetch(`${API_BASE_URL}/api/git/deploy/resolve`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ cancel: true }),
        });
        const result = await response.json();
        if (response.ok) {
            message.info(result.message || '部署已取消');
        } else {
            message.error(result.message || '操作失败');
        }
    } catch (error) {
        message.error('请求失败');
    }
  };

  const handleInstallDeps = async (packageManager) => {
    setIsInstallingDeps(true);
    setDepsLogs([]);
    setIsDepsModalVisible(true);
    setDepsProgress(0);

    try {
        const response = await fetch(`${API_BASE_URL}/api/git/install-deps`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ packageManager }),
        });
        
        if (!response.ok) {
            const result = await response.json();
            message.error(result.message || '启动依赖安装失败');
            setIsInstallingDeps(false);
        }
    } catch (error) {
        message.error('依赖安装请求失败');
        setIsInstallingDeps(false);
    }
  };

  const handleCancelDepsInstall = async () => {
    try {
        const response = await fetch(`${API_BASE_URL}/api/git/install-deps/cancel`, {
            method: 'POST',
        });
        const result = await response.json();
        if (result.success) {
            message.warning('取消安装请求已发送');
        } else {
            message.error(result.message || '取消失败');
        }
    } catch (error) {
        message.error('发送取消请求时出错');
    }
  };

  const handleRemoveDeps = async () => {
    setIsRemovingDeps(true);
    setDepsLogs([]);
    setIsDepsModalVisible(true);
    setDepsProgress(0);

    try {
        const response = await fetch(`${API_BASE_URL}/api/git/remove-deps`, {
            method: 'POST',
        });
        
        if (!response.ok) {
            const result = await response.json();
            message.error(result.message || '启动依赖移除失败');
            setIsRemovingDeps(false);
        }
    } catch (error) {
        message.error('依赖移除请求失败');
        setIsRemovingDeps(false);
    }
  };

  const handleCancelRemoveDeps = async () => {
    try {
        const response = await fetch(`${API_BASE_URL}/api/git/remove-deps/cancel`, {
            method: 'POST',
        });
        const result = await response.json();
        if (result.success) {
            message.warning('取消移除请求已发送');
        } else {
            message.error(result.message || '取消失败');
        }
    } catch (error) {
        message.error('发送取消请求时出错');
    }
  };

  const handleRestoreCode = async () => {
    setIsRestoring(true);
    const key = 'restore_message';
    message.loading({ content: '正在还原代码...', key });
    
    try {
        const response = await fetch(`${API_BASE_URL}/api/git/restore`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
        });
        const result = await response.json();
        
        if (result.success) {
            message.success({ content: result.message, key });
        } else {
            message.error({ content: result.message || '还原失败', key });
        }
    } catch (error) {
        message.error({ content: '还原代码时出错', key });
    } finally {
        setIsRestoring(false);
    }
  };



  return (
    <div className="git-manager" style={{ minHeight: '100vh' }}>
      <Title level={2}>Git 项目管理</Title>
      
      <div className="top-config-area">
        <Card title="项目路径配置" style={{ flex: 1, marginRight: '20px' }}>
          <Search
            placeholder="请输入Git项目在服务器上的绝对路径"
            enterButton={<><SaveOutlined /> 保存</>}
            size="large"
            value={inputRepoPath}
            onChange={(e) => setInputRepoPath(e.target.value)}
            onSearch={handleSaveRepoPath}
            loading={loading}
          />
        </Card>
        
        <Card title="依赖管理" style={{ width: 300, marginRight: '20px' }}>
          <div style={{ marginBottom: 12 }}>
            <Text strong>当前分支: </Text>
            <Text type={currentBranch ? "success" : "secondary"}>
              {currentBranch || '未选择分支'}
            </Text>
          </div>
          <Radio.Group 
            value={selectedPackageManager} 
            onChange={(e) => setSelectedPackageManager(e.target.value)}
            style={{ marginBottom: 12, display: 'block' }}
          >
            <Radio value="npm">npm</Radio>
            <Radio value="pnpm">pnpm</Radio>
            <Radio value="yarn">yarn</Radio>
          </Radio.Group>
          <div style={{ display: 'flex', gap: '8px', flexDirection: 'column' }}>
            <Button 
              type="primary"
              icon={<DownloadOutlined />} 
              loading={isInstallingDeps}
              disabled={!currentBranch || isInstallingDeps || isRemovingDeps}
              onClick={() => handleInstallDeps(selectedPackageManager)}
              block
            >
              {isInstallingDeps ? '正在安装...' : '更新依赖'}
            </Button>
            <Popconfirm
              title="确定要移除 node_modules 文件夹吗？"
              description="此操作将删除整个 node_modules 目录，需要重新安装依赖才能正常运行项目。"
              onConfirm={handleRemoveDeps}
              okText="确认移除"
              cancelText="取消"
              disabled={!currentBranch || isInstallingDeps || isRemovingDeps}
            >
              <Button 
                danger
                icon={<DeleteOutlined />} 
                loading={isRemovingDeps}
                disabled={!currentBranch || isInstallingDeps || isRemovingDeps}
                block
              >
                {isRemovingDeps ? '正在移除...' : '移除依赖'}
              </Button>
            </Popconfirm>
            <Popconfirm
              title="确定要还原当前分支的所有改动吗？"
              description="此操作将执行 git reset --hard，放弃当前分支的所有未提交改动，且无法撤销。"
              onConfirm={handleRestoreCode}
              okText="确认还原"
              cancelText="取消"
              disabled={!currentBranch || isInstallingDeps || isRemovingDeps || isRestoring}
            >
              <Button 
                icon={<UndoOutlined />} 
                loading={isRestoring}
                disabled={!currentBranch || isInstallingDeps || isRemovingDeps || isRestoring}
                block
                style={{ marginTop: 8 }}
              >
                {isRestoring ? '正在还原...' : '还原'}
              </Button>
            </Popconfirm>
          </div>
        </Card>
        
        <Card title="在线用户" style={{ width: 280 }}>
          <Text><UserOutlined /> 当前 {onlineUsers.length} 人在线</Text>
          <div style={{ marginTop: 8, display: 'flex', flexWrap: 'wrap', gap: 4 }}>
            {onlineUsers.map(user => (
              <Tooltip key={user.ip + user.connectedAt} title={`连接于: ${new Date(user.connectedAt).toLocaleString()}`}>
                <Tag>{user.ip}</Tag>
              </Tooltip>
            ))}
          </div>
        </Card>
      </div>

      <Tabs defaultActiveKey="1" type="card" style={{ marginTop: 20 }}>
        <TabPane tab="分支列表" key="1">
          <Card
            title="分支列表"
            extra={repoPath && <Button icon={<SyncOutlined />} onClick={fetchBranches} loading={loadingBranches}>刷新</Button>}
            tabList={[{ key: 'favorites', tab: '常用分支' }, { key: 'others', tab: '不常用分支' }, { key: 'all', tab: '全部分支' }]}
            activeTabKey={activeTab}
            onTabChange={key => setActiveTab(key)}
          >
            {loadingBranches ? (
              <div style={{ textAlign: 'center', padding: '50px' }}><Spin size="large" /></div>
            ) : (
              <List
                itemLayout="horizontal"
                dataSource={filteredBranches}
                locale={{ emptyText: repoPath ? '此分类下没有分支。' : '请先配置项目路径' }}
                renderItem={item => {
                  const isCurrent = item.name === currentBranch;
                  const isEditing = editingRemark === item.name;
                  const isProduction = item.name === productionBranch;

                  return (
                    <List.Item
                      actions={[
                        isProduction && (
                          !isCurrent ? (
                            <Tooltip title="请先将项目切换到此分支再进行部署">
                              <span>
                                <Button 
                                  type="primary" 
                                  danger 
                                  icon={<RocketOutlined />} 
                                  disabled
                                >
                                  构建并部署
                                </Button>
                              </span>
                            </Tooltip>
                          ) : (
                            <Button 
                              type="primary" 
                              danger 
                              icon={<RocketOutlined />} 
                              loading={isDeploying}
                              onClick={() => showDeployConfirm(item.name)}
                            >
                              构建并部署
                            </Button>
                          )
                        ),
                        <Tooltip title={item.isFavorite ? '从常用中移除' : '添加到常用'}>
                          <Button shape="circle" icon={item.isFavorite ? <StarFilled style={{color: '#ffc53d'}} /> : <StarOutlined />} onClick={() => handleToggleFavorite(item.name, item.isFavorite)} />
                        </Tooltip>,
                        <Tooltip title={isCurrent ? "拉取最新代码" : "切换到此分支并拉取最新代码"}>
                          <Button icon={<SyncOutlined />} loading={pullingBranch === item.name} onClick={() => handlePull(item.name)}>
                            {isCurrent ? '拉取' : '切换并拉取'}
                          </Button>
                        </Tooltip>,
                        <Popconfirm 
                          title={`确定要切换到分支 ${item.name} 吗？这会影响所有在线用户。`} 
                          onConfirm={() => handleCheckout(item.name)} 
                          okText="确定切换" 
                          cancelText="取消" 
                          disabled={isCurrent}
                        >
                          <Tooltip title="仅切换分支，不拉取代码。此操作会影响所有在线用户。">
                            <Button icon={<ForkOutlined />} disabled={isCurrent}>仅切换</Button>
                          </Tooltip>
                        </Popconfirm>,
                        isEditing ? (
                          <Button icon={<CheckOutlined />} onClick={() => handleSaveRemark(item.name)} type="primary">保存</Button>
                        ) : (
                          <Button icon={<EditOutlined />} onClick={() => { setEditingRemark(item.name); setRemarkInput(item.remark); }}>备注</Button>
                        ),
                      ]}
                    >
                      <List.Item.Meta
                        title={<>
                          <Text strong style={{ color: isCurrent ? '#1890ff' : 'inherit' }}>{item.name}</Text>
                          {isCurrent && <Tag color="blue" style={{ marginLeft: 8 }}>当前分支</Tag>}
                          {isProduction && <Tag color="green" style={{ marginLeft: 8 }}>生产分支</Tag>}
                        </>}
                        description={isEditing ? (
                          <Input value={remarkInput} onChange={e => setRemarkInput(e.target.value)} onPressEnter={() => handleSaveRemark(item.name)} />
                        ) : (
                          item.remark || <Text type="secondary">暂无备注</Text>
                        )}
                      />
                    </List.Item>
                  )
                }}
              />
            )}
          </Card>
        </TabPane>
        <TabPane tab="推送配置" key="2">
          <Card title="生产环境配置" className="production-config-card">
            <Form layout="vertical" onFinish={handleSaveProductionConfig} form={configForm} initialValues={sshConfig}>
              <Form.Item name="productionBranch" label="生产分支名称" rules={[{ required: true }]}>
                <Input placeholder="例如：main 或 master" />
              </Form.Item>
              <Title level={5}>SSH 配置</Title>
              <Form.Item name="host" label="SSH 主机" rules={[{ required: true }]}>
                <Input placeholder="例如：127.0.0.1" />
              </Form.Item>
               <Form.Item name="port" label="SSH 端口" initialValue={22}>
                <InputNumber placeholder="默认: 22" style={{ width: '100%' }} />
              </Form.Item>
              <Form.Item name="username" label="SSH 用户名" rules={[{ required: true }]}>
                <Input />
              </Form.Item>
              <Form.Item name="privateKeyPath" label="私钥文件路径" rules={[{ required: true }]}>
                <Input placeholder="例如: public/blacktom-deploy" />
              </Form.Item>
              <Form.Item name="remotePath" label="远程目录" rules={[{ required: true }]}>
                <Input placeholder="例如：/www/wwwroot/your-site" />
              </Form.Item>
              <Form.Item name="buildDir" label="构建输出目录" rules={[{ required: true }]}>
                <Input placeholder="例如：dist 或 build" />
              </Form.Item>
              <Form.Item name="defaultPerms" label="新文件权限" initialValue="755">
                <Input placeholder="默认: 755" />
                <div style={{ fontSize: '12px', color: '#666', marginTop: '4px' }}>
                  💡 覆盖时保持原权限，新文件使用此权限（文件和目录统一）
                </div>
              </Form.Item>
              <Form.Item name="owner" label="默认所有者" initialValue="www:www">
                <Input placeholder="例如: www:www" />
                <div style={{ fontSize: '12px', color: '#666', marginTop: '4px' }}>
                  💡 新文件的所有者设置
                </div>
              </Form.Item>
              <Form.Item>
                <Button type="primary" htmlType="submit" icon={<SaveOutlined />} loading={loading} style={{ marginRight: 8 }}>
                  保存生产配置
                </Button>
                {/* <Button onClick={handleTestSsh} loading={isTestingSsh} disabled={isDeploying}>
                    测试 SSH 连接
                </Button> */}
              </Form.Item>
            </Form>
          </Card>
        </TabPane>
      </Tabs>

      <Modal
        title={isTestingSsh ? "SSH 连接测试日志" : "部署日志"}
        open={isDeployModalVisible}
        onCancel={() => setIsDeployModalVisible(false)}
        footer={[
          isDeploying ? (
            <Button key="cancel" type="primary" danger onClick={() => handleCancelDeploy(productionBranch)}>
              取消部署
            </Button>
          ) : null,
          <Button key="close" onClick={() => setIsDeployModalVisible(false)} disabled={isDeploying || isTestingSsh}>
            {isDeploying ? '正在部署...' : (isTestingSsh ? '正在测试...' : '关闭')}
          </Button>,
        ]}
        width={800}
      >
        {isUploading && <Progress 
            percent={uploadProgress} 
            status="active" 
            style={{ marginBottom: 10 }}
            format={(percent) => `${currentStage === 'zip' ? '压缩中' : '上传中'}: ${percent}%`}
        />}
        <div ref={deployLogRef} style={{ height: 400, overflowY: 'auto', background: '#000', color: '#fff', padding: 10, borderRadius: 4, whiteSpace: 'pre-wrap', fontFamily: 'monospace' }}>
          {deployLogs.map((log, index) => (
            <div key={index}>{log}</div>
          ))}
          {(isDeploying || isTestingSsh) && !isUploading && !deployLogs.some(log => log.includes('完成') || log.includes('失败')) && (
            <div style={{ display: 'flex', alignItems: 'center' }}>
              <Spin size="small" style={{ marginRight: 8 }} /> 等待日志输出...
            </div>
          )}
        </div>
      </Modal>

      <Modal
        title="文件覆盖确认"
        visible={isConflictModalVisible}
        onCancel={handleCancelConflict}
        footer={[
            <Button key="cancel" onClick={handleCancelConflict}>
                取消部署
            </Button>,
            <Button key="submit" type="primary" onClick={() => handleResolveConflict(selectedFiles)}>
                覆盖选中并部署
            </Button>,
        ]}
      >
        <p>检测到 <strong>{conflictFiles.length}</strong> 个文件/目录已存在于目标位置。请选择需要覆盖的项目：</p>
        <Checkbox
            onChange={(e) => setSelectedFiles(e.target.checked ? conflictFiles.map(f => f.name) : [])}
            checked={selectedFiles.length === conflictFiles.length && conflictFiles.length > 0}
            indeterminate={selectedFiles.length > 0 && selectedFiles.length < conflictFiles.length}
        >
            全选
        </Checkbox>
        <Divider />
        <div style={{ height: 200, overflowY: 'auto', border: '1px solid #f0f0f0' }}>
            <List
                dataSource={conflictFiles}
                renderItem={(item) => (
                    <List.Item>
                        <Checkbox 
                            value={item.name}
                            checked={selectedFiles.includes(item.name)}
                            onChange={(e) => {
                                const newSelected = e.target.checked
                                    ? [...selectedFiles, item.name]
                                    : selectedFiles.filter(name => name !== item.name);
                                setSelectedFiles(newSelected);
                            }}
                        >
                            {item.type === 'dir' ? <FolderOutlined style={{ marginRight: 8 }} /> : <FileOutlined style={{ marginRight: 8 }} />}
                            {item.name}
                        </Checkbox>
                    </List.Item>
                )}
            />
        </div>
      </Modal>

      <Modal
        title={isRemovingDeps ? "依赖移除日志" : "依赖安装日志"}
        open={isDepsModalVisible}
        onCancel={() => setIsDepsModalVisible(false)}
        footer={[
          isInstallingDeps ? (
            <Button key="cancel" type="primary" danger onClick={handleCancelDepsInstall}>
              取消安装
            </Button>
          ) : isRemovingDeps ? (
            <Button key="cancel" type="primary" danger onClick={handleCancelRemoveDeps}>
              取消移除
            </Button>
          ) : null,
          <Button key="close" onClick={() => setIsDepsModalVisible(false)} disabled={isInstallingDeps || isRemovingDeps}>
            {isInstallingDeps ? '正在安装...' : isRemovingDeps ? '正在移除...' : '关闭'}
          </Button>,
        ]}
        width={800}
      >
        {(isInstallingDeps || isRemovingDeps) && <Progress 
            percent={depsProgress} 
            status="active" 
            style={{ marginBottom: 10 }}
            format={(percent) => `${isRemovingDeps ? '移除' : '安装'}进度: ${percent}%`}
        />}
        <div ref={depsLogRef} style={{ height: 400, overflowY: 'auto', background: '#000', color: '#fff', padding: 10, borderRadius: 4, whiteSpace: 'pre-wrap', fontFamily: 'monospace' }}>
          {depsLogs.map((log, index) => (
            <div key={index}>{log}</div>
          ))}
          {(isInstallingDeps || isRemovingDeps) && !depsLogs.some(log => log.includes('完成') || log.includes('失败')) && (
            <div style={{ display: 'flex', alignItems: 'center' }}>
              <Spin size="small" style={{ marginRight: 8 }} /> 等待日志输出...
            </div>
          )}
        </div>
      </Modal>

    </div>
  );
};

export default GitManager; 